package com.yupi.springbootinit.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yupi.springbootinit.mapper.*;
import com.yupi.springbootinit.model.entity.*;
import com.yupi.springbootinit.model.vo.WorkflowTaskVO;
import com.yupi.springbootinit.model.vo.production.PmcSetupVO;
import com.yupi.springbootinit.service.BatchCodeGeneratorService;
import com.yupi.springbootinit.model.vo.production.ProcessStepVO;
import com.yupi.springbootinit.service.ProductionTaskQueryService;
import com.yupi.springbootinit.utils.JsonUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 生产任务查询服务实现
 */
@Slf4j
@Service
public class ProductionTaskQueryServiceImpl implements ProductionTaskQueryService {

    // ==================== 常量定义 ====================
    private static final String PRODUCTION_DEPT_CODE = "SC001";
    private static final String STATUS_PENDING = "PENDING";
    private static final String STATUS_IN_PROGRESS = "IN_PROGRESS";
    private static final String STATUS_DONE = "DONE";

    // ==================== 依赖注入 ====================
    @Resource
    private WorkflowTaskMapper workflowTaskMapper;
    @Resource
    private DepartmentMapper departmentMapper;
    @Resource
    private ProcessBatchMapper processBatchMapper;
    @Resource
    private ProcessSheetProductMapper processSheetProductMapper;
    @Resource
    private ProcessSheetBatchProductMapper processSheetBatchProductMapper;

    @Resource
    private ProcessSheetMapper processSheetMapper;

    @Resource
    private ProcessBatchStepMapper processBatchStepMapper;
    
    @Resource
    private BatchCodeGeneratorService batchCodeGeneratorService;

    // ==================== 接口实现 ====================

    @Override
    public Page<WorkflowTaskVO> pageAvailableTasks(Long userId, String status, long current, long size) {
        LambdaQueryWrapper<WorkflowTask> qw = new LambdaQueryWrapper<>();

        Long prodDeptId = getProductionDeptId();
        if (prodDeptId != null) {
            qw.eq(WorkflowTask::getDepartmentId, prodDeptId)
                    .eq(WorkflowTask::getIsDelete, 0);
        } else {
            qw.like(WorkflowTask::getTaskType, "PRODUCTION")
                    .eq(WorkflowTask::getIsDelete, 0);
        }

        // 支持 status=ALL（不加任务状态过滤）
        if (StringUtils.isNotBlank(status)) {
            if (!"ALL".equalsIgnoreCase(status)) {
                qw.eq(WorkflowTask::getTaskStatus, status);
            }
        } else {
            qw.eq(WorkflowTask::getTaskStatus, STATUS_PENDING);
        }

        qw.orderByDesc(WorkflowTask::getCreateTime);

        Page<WorkflowTask> page = workflowTaskMapper.selectPage(new Page<>(current, size), qw);

        Page<WorkflowTaskVO> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        List<WorkflowTaskVO> voList = page.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    public Page<WorkflowTaskVO> pageMyProductionTasks(Long userId, String status, long current, long size) {
        if (userId == null) {
            return new Page<>(current, size, 0);
        }

        LambdaQueryWrapper<WorkflowTask> qw = new LambdaQueryWrapper<>();
        qw.eq(WorkflowTask::getClaimedBy, userId);

        Long prodDeptId = getProductionDeptId();
        if (prodDeptId != null) {
            qw.eq(WorkflowTask::getDepartmentId, prodDeptId)
                    .eq(WorkflowTask::getIsDelete, 0);
        } else {
            qw.like(WorkflowTask::getTaskType, "PRODUCTION")
                    .eq(WorkflowTask::getIsDelete, 0);
        }

        if (StringUtils.isNotBlank(status)) {
            qw.eq(WorkflowTask::getTaskStatus, status);
        }

        qw.orderByDesc(WorkflowTask::getUpdateTime);

        Page<WorkflowTask> page = workflowTaskMapper.selectPage(new Page<>(current, size), qw);

        Page<WorkflowTaskVO> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        List<WorkflowTaskVO> voList = page.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    public Page<WorkflowTaskVO> pageCleaningTasks(Long userId, String status, long current, long size) {
        if (userId == null) {
            return new Page<>(current, size, 0);
        }

        // 参数校验
        if (current <= 0) current = 1;
        if (size <= 0 || size > 100) size = 20;

        LambdaQueryWrapper<WorkflowTask> qw = new LambdaQueryWrapper<>();
        qw.eq(WorkflowTask::getDepartmentId, getProductionDeptId())
                .eq(WorkflowTask::getTaskType, "PRODUCTION_PREP_CLEANING")
                .eq(WorkflowTask::getIsDelete, 0);

        if (StringUtils.isNotBlank(status)) {
            qw.eq(WorkflowTask::getTaskStatus, status);
        } else {
            qw.ne(WorkflowTask::getTaskStatus, STATUS_DONE);
        }

        qw.orderByDesc(WorkflowTask::getCreateTime);

        Page<WorkflowTask> page = workflowTaskMapper.selectPage(new Page<>(current, size), qw);

        Page<WorkflowTaskVO> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        List<WorkflowTaskVO> voList = page.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        // ==================== 新增：批量填充产品、材料、设备信息 ====================
        enrichCleaningTasksWithDetails(voList);

        voPage.setRecords(voList);
        return voPage;
    }


    @Override
    public Page<WorkflowTaskVO> pageProductionTasks(Long userId, String status, long current, long size) {
        if (userId == null) {
            return new Page<>(current, size, 0);
        }

        if (current <= 0) current = 1;
        if (size <= 0 || size > 100) size = 20;

        LambdaQueryWrapper<WorkflowTask> qw = new LambdaQueryWrapper<>();
        qw.eq(WorkflowTask::getDepartmentId, getProductionDeptId())
                .eq(WorkflowTask::getTaskType, "PRODUCTION_WORKORDER")
                .eq(WorkflowTask::getIsDelete, 0);

        if (StringUtils.isNotBlank(status)) {
            qw.eq(WorkflowTask::getTaskStatus, status);
        } else {
            qw.ne(WorkflowTask::getTaskStatus, STATUS_DONE);
        }

        qw.apply("EXISTS (SELECT 1 FROM workflow_task wt2 " +
                "WHERE wt2.bizType = 'PROCESS_BATCH' " +
                "AND wt2.bizId = workflow_task.bizId " +
                "AND wt2.taskType = 'PRODUCTION_PREP_CLEANING' " +
                "AND wt2.taskStatus = 'DONE' " +
                "AND wt2.isDelete = 0)");

        qw.orderByDesc(WorkflowTask::getCreateTime);

        Page<WorkflowTask> page = workflowTaskMapper.selectPage(new Page<>(current, size), qw);

        Page<WorkflowTaskVO> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        List<WorkflowTaskVO> voList = page.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());

        enrichCleaningTasksWithDetails(voList);
        enrichProductionTasksWithSteps(voList);

        voPage.setRecords(voList);
        return voPage;
    }
    @Override
    public WorkflowTaskVO getTaskDetail(Long taskId) {
        if (taskId == null) return null;

        WorkflowTask task = workflowTaskMapper.selectById(taskId);
        if (task == null || task.getIsDelete() == 1) return null;

        WorkflowTaskVO taskVO = convertToVO(task);

        if (task.getDepartmentId() != null) {
            Department dept = departmentMapper.selectById(task.getDepartmentId());
            if (dept != null) {
                boolean needClaim = (dept.getRequireTaskClaim() == null || dept.getRequireTaskClaim() == 1);
                taskVO.setRequireClaim(needClaim);
            } else {
                taskVO.setRequireClaim(true);
            }
        } else {
            taskVO.setRequireClaim(true);
        }

        if ("CREATE_SCHEDULE".equals(task.getTaskType()) && "SALES_ORDER".equals(task.getBizType())) {
            try {
                ProcessSheet processSheet = processSheetMapper.selectOne(
                        new LambdaQueryWrapper<ProcessSheet>()
                                .eq(ProcessSheet::getSourceId, task.getBizId())
                                .eq(ProcessSheet::getSourceType, 1)
                                .eq(ProcessSheet::getIsDeleted, 0)
                );
                if (processSheet != null) {
                    taskVO.setProcessSheetId(processSheet.getId());
                    taskVO.setProcessSheetNo(processSheet.getProcessSheetNo());
                    Map<String, Object> extInfo = new HashMap<>();
                    extInfo.put("quantity", processSheet.getQuantity());
                    extInfo.put("processStatus", processSheet.getProcessStatus());
                    extInfo.put("startProductionTime", processSheet.getCreateTime());

                    try {
                        ObjectMapper mapper = JsonUtils.getMapper();
                        taskVO.setExtendedInfo(mapper.writeValueAsString(extInfo));
                    } catch (Exception ex) {
                        log.warn("序列化扩展信息失败: taskId={}", taskId, ex);
                    }
                }
            } catch (Exception e) {
                log.warn("获取工艺单信息失败: taskId={}, bizId={}", taskId, task.getBizId(), e);
            }
        }

        if (("PRODUCTION_PREP_CLEANING".equals(task.getTaskType())
                || "PRODUCTION_WORKORDER".equals(task.getTaskType()))
                && "PROCESS_BATCH".equals(task.getBizType())) {
            try {
                Long batchId = extractBatchIdFromTask(task);
                if (batchId != null) {
                    ProcessBatch batch = processBatchMapper.selectById(batchId);
                    if (batch != null) {
                        taskVO.setBatchCode(batch.getBatchCode());
                        taskVO.setFlowNumber(batch.getFlowNumber());
                        taskVO.setProductionPlanNumber(batch.getProductionPlanNumber());

                        Map<String, Object> extInfo = new HashMap<>();
                        extInfo.put("powderWeight", batch.getPowderWeight());
                        extInfo.put("powderModel", batch.getPowderModel());
                        extInfo.put("cleaningDeviceName", batch.getCleaningDeviceName());
                        extInfo.put("cleaningDeviceId", batch.getCleaningDeviceId());

                        if ("PRODUCTION_WORKORDER".equals(task.getTaskType())) {
                            extInfo.put("startProductionTime", batch.getPlanStart());
                        }

                        try {
                            taskVO.setExtendedInfo(JsonUtils.toJson(extInfo));
                        } catch (Exception ex) {
                            log.warn("序列化批次信息失败: taskId={}, batchId={}", taskId, batchId, ex);
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("获取批次信息失败: taskId={}", taskId, e);
            }
        }

        return taskVO;
    }

    @Override
    public PmcSetupVO getPmcSetup(Long taskId) {
        if (taskId == null) {
            return null;
        }

        Long batchId = extractBatchIdFromTask(taskId);
        if (batchId == null) {
            return null;
        }

        ProcessBatch batch = processBatchMapper.selectById(batchId);
        if (batch == null || batch.getIsDeleted() != null && batch.getIsDeleted() == 1) {
            return null;
        }

        PmcSetupVO vo = new PmcSetupVO();
        vo.setTaskId(taskId);
        vo.setBatchId(batchId);
        vo.setBatchCode(batch.getBatchCode());
        vo.setPowderModel(batch.getPowderModel());
        vo.setPowderWeight(batch.getPowderWeight());
        vo.setCleaningDeviceId(batch.getCleaningDeviceId());
        vo.setCleaningDeviceName(batch.getCleaningDeviceName());
        vo.setPlanStart(batch.getPlanStart());
        return vo;
    }

    // ==================== 私有辅助方法 ====================

    /**
     * 获取生产部门ID
     */
    private Long getProductionDeptId() {
        Department prodDept = departmentMapper.selectOne(
                new LambdaQueryWrapper<Department>()
                        .eq(Department::getDepartmentCode, PRODUCTION_DEPT_CODE)
                        .eq(Department::getIsDelete, 0)
                        .last("LIMIT 1")
        );
        return prodDept != null ? prodDept.getId() : null;
    }

    /**
     * 从任务中提取批次ID
     */
    private Long extractBatchIdFromTask(Long taskId) {
        if (taskId == null) return null;
        WorkflowTask task = workflowTaskMapper.selectById(taskId);
        return extractBatchIdFromTask(task);
    }

    private Long extractBatchIdFromTask(WorkflowTask task) {
        if (task != null && "PROCESS_BATCH".equals(task.getBizType())) {
            return task.getBizId();
        }
        return task != null ? task.getBizId() : null;
    }

    /**
     * 转换任务实体为 VO
     */
    private WorkflowTaskVO convertToVO(WorkflowTask task) {
        WorkflowTaskVO vo = new WorkflowTaskVO();
        BeanUtils.copyProperties(task, vo);
        vo.setTaskStatusName(getStatusDisplayName(task.getTaskStatus(), task.getTaskType()));
        vo.setIsClaimed(task.getClaimedBy() != null);
        vo.setCanClaim(STATUS_PENDING.equals(task.getTaskStatus()) && task.getClaimedBy() == null);
        vo.setIsOverdue(isTaskOverdue(task));

        // 附加部门认领配置
        if (task.getDepartmentId() != null) {
            Department dept = departmentMapper.selectById(task.getDepartmentId());
            if (dept != null) {
                boolean needClaim = (dept.getRequireTaskClaim() == null || dept.getRequireTaskClaim() == 1);
                vo.setRequireClaim(needClaim);
            } else {
                vo.setRequireClaim(true);
            }
        } else {
            vo.setRequireClaim(true);
        }

        // PMC任务补充工艺单信息
        if ("CREATE_SCHEDULE".equals(task.getTaskType()) && "SALES_ORDER".equals(task.getBizType())) {
            enrichPmcTaskWithProcessSheet(vo, task);
        }

        return vo;
    }

    /**
     * 补充PMC任务的工艺单信息
     */
    private void enrichPmcTaskWithProcessSheet(WorkflowTaskVO taskVO, WorkflowTask task) {
        try {
            ProcessSheet processSheet = processSheetMapper.selectOne(
                    new LambdaQueryWrapper<ProcessSheet>()
                            .eq(ProcessSheet::getSourceId, task.getBizId())
                            .eq(ProcessSheet::getSourceType, 1)
                            .eq(ProcessSheet::getIsDeleted, 0)
            );
            if (processSheet != null) {
                taskVO.setProcessSheetId(processSheet.getId());
                taskVO.setProcessSheetNo(processSheet.getProcessSheetNo());
            }
        } catch (Exception e) {
            log.warn("补充工艺单信息失败: taskId={}, bizId={}", task.getId(), task.getBizId(), e);
        }
    }

    /**
     * 获取任务状态显示名称
     */
    private String getStatusDisplayName(String status, String taskType) {
        if (StringUtils.isBlank(status)) return "";

        if ("PRODUCTION_PREP_CLEANING".equals(taskType)) {
            switch (status) {
                case STATUS_PENDING: return "待烘粉清机";
                case STATUS_IN_PROGRESS: return "烘粉清机中";
                case STATUS_DONE: return "烘粉清机完成";
                default: return status;
            }
        } else if ("PRODUCTION_WORKORDER".equals(taskType)) {
            switch (status) {
                case STATUS_PENDING: return "待生产";
                case STATUS_IN_PROGRESS: return "生产中";
                case STATUS_DONE: return "生产完成";
                default: return status;
            }
        } else {
            switch (status) {
                case STATUS_PENDING: return "待认领";
                case STATUS_IN_PROGRESS: return "进行中";
                case STATUS_DONE: return "已完成";
                default: return status;
            }
        }
    }

    /**
     * 判断任务是否逾期
     */
    private boolean isTaskOverdue(WorkflowTask task) {
        if (task.getExpectedCompleteTime() == null) return false;
        return LocalDateTime.now().isAfter(task.getExpectedCompleteTime())
                && !STATUS_DONE.equals(task.getTaskStatus());
    }

    /**
     * 批量填充清机任务的产品、材料、设备信息
     */
    private void enrichCleaningTasksWithDetails(List<WorkflowTaskVO> voList) {
        if (voList == null || voList.isEmpty()) {
            return;
        }

        try {
            Set<Long> batchIds = voList.stream()
                    .map(WorkflowTaskVO::getBizId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            if (batchIds.isEmpty()) {
                return;
            }

            List<ProcessBatch> batches = processBatchMapper.selectBatchIds(batchIds);
            Map<Long, ProcessBatch> batchMap = batches.stream()
                    .collect(Collectors.toMap(ProcessBatch::getId, b -> b, (a, b) -> a));

            // 【修改】查询工艺单信息
            Set<Long> processSheetIds = batches.stream()
                    .map(ProcessBatch::getProcessSheetId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());
            Map<Long, ProcessSheet> processSheetMap = new HashMap<>();
            if (!processSheetIds.isEmpty()) {
                List<ProcessSheet> processSheets = processSheetMapper.selectBatchIds(new ArrayList<>(processSheetIds));
                if (processSheets != null && !processSheets.isEmpty()) {
                    processSheetMap = processSheets.stream()
                            .collect(Collectors.toMap(ProcessSheet::getId, ps -> ps, (a, b) -> a));
                }
            }

            Set<Long> batchPlanIds = batches.stream()
                    .map(ProcessBatch::getBatchPlanId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            if (batchPlanIds.isEmpty()) {
                return;
            }

            Map<Long, List<ProcessSheetBatchProduct>> batchProductsMap = new HashMap<>();
            LambdaQueryWrapper<ProcessSheetBatchProduct> productQw = new LambdaQueryWrapper<>();
            productQw.in(ProcessSheetBatchProduct::getBatchId, batchPlanIds)
                    .eq(ProcessSheetBatchProduct::getIsDeleted, 0);
            List<ProcessSheetBatchProduct> allBatchProducts = processSheetBatchProductMapper.selectList(productQw);

            batchProductsMap = allBatchProducts.stream()
                    .collect(Collectors.groupingBy(ProcessSheetBatchProduct::getBatchId));

            Set<Long> productIds = batchProductsMap.values().stream()
                    .flatMap(List::stream)
                    .map(ProcessSheetBatchProduct::getProductId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            // 【修改】通过 processSheetId 查询所有产品明细，然后通过 productId 或 productCode 匹配
            Map<Long, ProcessSheetProduct> productDetailMap = new HashMap<>();
            // 先尝试通过 productId 批量查询
            if (!productIds.isEmpty()) {
                List<ProcessSheetProduct> products = processSheetProductMapper.selectBatchIds(new ArrayList<>(productIds));
                if (products != null && !products.isEmpty()) {
                    productDetailMap = products.stream()
                            .collect(Collectors.toMap(ProcessSheetProduct::getId, p -> p, (a, b) -> a));
                    log.debug("通过 productId 查询到产品明细: productIds={}, 查询结果数量={}", productIds.size(), products.size());
                }
            }
            
            // 如果通过 productId 查询不到，尝试通过 processSheetId + productCode 查询
            if (productDetailMap.isEmpty() && !processSheetIds.isEmpty() && !batchProductsMap.isEmpty()) {
                // 收集所有需要查询的 productCode
                Set<String> productCodes = batchProductsMap.values().stream()
                        .flatMap(List::stream)
                        .map(ProcessSheetBatchProduct::getProductCode)
                        .filter(StringUtils::isNotBlank)
                        .collect(Collectors.toSet());
                
                // 为每个 processSheetId 查询产品明细
                for (Long processSheetId : processSheetIds) {
                    List<ProcessSheetProduct> sheetProducts = processSheetProductMapper.selectList(
                            new LambdaQueryWrapper<ProcessSheetProduct>()
                                    .eq(ProcessSheetProduct::getProcessSheetId, processSheetId)
                                    .in(ProcessSheetProduct::getProductCode, productCodes)
                                    .eq(ProcessSheetProduct::getIsDeleted, 0)
                    );
                    if (sheetProducts != null && !sheetProducts.isEmpty()) {
                        // 通过 productCode 匹配 batchProduct，建立 productId 映射
                        for (ProcessSheetProduct product : sheetProducts) {
                            for (List<ProcessSheetBatchProduct> bpList : batchProductsMap.values()) {
                                for (ProcessSheetBatchProduct bp : bpList) {
                                    if (product.getProductCode().equals(bp.getProductCode())) {
                                        productDetailMap.put(bp.getProductId(), product);
                                        log.debug("通过 productCode 匹配产品: productCode={}, batchProductId={}, productId={}",
                                                product.getProductCode(), bp.getProductId(), product.getId());
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                
                if (!productDetailMap.isEmpty()) {
                    log.info("通过 productCode 查询到产品明细: processSheetIds={}, 查询结果数量={}", processSheetIds, productDetailMap.size());
                }
            }
            
            // 调试日志
            if (!productDetailMap.isEmpty()) {
                productDetailMap.values().forEach(p -> {
                    log.debug("产品明细: id={}, productCode={}, productHeight={}, unitWeight={}, partDrawingNo={}",
                            p.getId(), p.getProductCode(), p.getProductHeight(), p.getUnitWeight(), p.getPartDrawingNo());
                });
            } else {
                log.warn("未查询到产品明细: productIds={}, processSheetIds={}", productIds, processSheetIds);
            }

            for (WorkflowTaskVO vo : voList) {
                Long batchId = vo.getBizId();
                if (batchId == null) continue;

                ProcessBatch batch = batchMap.get(batchId);
                if (batch == null || batch.getBatchPlanId() == null) continue;

                vo.setBatchCode(batch.getBatchCode());
                vo.setFlowNumber(batch.getFlowNumber());
                vo.setProductionPlanNumber(batch.getProductionPlanNumber());



                // 【修改】设置工艺单信息
                if (batch.getProcessSheetId() != null) {
                    ProcessSheet processSheet = processSheetMap.get(batch.getProcessSheetId());
                    if (processSheet != null) {
                        vo.setProcessSheetId(batch.getProcessSheetId());
                        vo.setProcessSheetNo(batchCodeGeneratorService.buildFullProcessSheetNo(
                                processSheet.getProcessSheetNo(),
                                processSheet.getProcessVersion()
                        ));
                    }
                }

                WorkflowTaskVO.DeviceInfo deviceInfo = new WorkflowTaskVO.DeviceInfo();
                deviceInfo.setDeviceId(batch.getDeviceId());
                deviceInfo.setDeviceCode(batch.getDeviceCode());
                deviceInfo.setDeviceName(batch.getDeviceName());
                deviceInfo.setCleaningDeviceId(batch.getCleaningDeviceId());
                deviceInfo.setCleaningDeviceName(batch.getCleaningDeviceName());
                vo.setDeviceInfo(deviceInfo);

                // 【修改】设置材料信息：从工艺单获取 materialBrand、materialSpec、powderSupplier
                WorkflowTaskVO.MaterialInfo materialInfo = new WorkflowTaskVO.MaterialInfo();
                if (batch.getProcessSheetId() != null) {
                    ProcessSheet processSheet = processSheetMap.get(batch.getProcessSheetId());
                    if (processSheet != null) {
                        materialInfo.setMaterialBrand(processSheet.getMaterialBrand());
                        materialInfo.setMaterialSpec(processSheet.getMaterialSpec());
                        materialInfo.setPowderSupplier(processSheet.getPowderSupplier());
                    }
                }

                vo.setMaterialInfo(materialInfo);

                List<ProcessSheetBatchProduct> batchProducts = batchProductsMap.get(batch.getBatchPlanId());
                if (batchProducts != null && !batchProducts.isEmpty()) {
                    Map<Long, ProcessSheetProduct> finalProductMap = productDetailMap;
                    List<WorkflowTaskVO.BatchProductInfo> productInfos = batchProducts.stream()
                            .map(bp -> {
                                WorkflowTaskVO.BatchProductInfo info = new WorkflowTaskVO.BatchProductInfo();
                                info.setProductName(bp.getProductName());
                                info.setQuantity(bp.getProductionQuantity());

                                // 【修改】优先从 ProcessSheetBatchProduct 获取 productCode，如果为空则从 ProcessSheetProduct 获取
                                if (bp.getProductId() != null) {
                                    ProcessSheetProduct detail = finalProductMap.get(bp.getProductId());
                                    if (detail != null) {
                                        // productCode 优先使用 ProcessSheetBatchProduct 中的，如果为空则使用 ProcessSheetProduct 中的
                                        if (StringUtils.isNotBlank(bp.getProductCode())) {
                                            info.setProductCode(bp.getProductCode());
                                        } else {
                                            info.setProductCode(detail.getProductCode());
                                        }
                                        info.setSpecification(detail.getSpecification());
                                        info.setProductHeight(detail.getProductHeight());
                                        info.setPartDrawingNo(detail.getPartDrawingNo());
                                        info.setUnitWeight(detail.getUnitWeight());
                                        
                                        // 调试日志
                                        if (detail.getProductHeight() == null) {
                                            log.debug("产品明细 productHeight 为空: productId={}, productCode={}, productName={}",
                                                    bp.getProductId(), detail.getProductCode(), detail.getProductName());
                                        }
                                    } else {
                                        // 如果找不到 ProcessSheetProduct，使用 ProcessSheetBatchProduct 中的 productCode
                                        info.setProductCode(bp.getProductCode());
                                        log.warn("未找到产品明细: productId={}, batchId={}, productCode={}",
                                                bp.getProductId(), bp.getBatchId(), bp.getProductCode());
                                    }
                                } else {
                                    // 如果 productId 为空，使用 ProcessSheetBatchProduct 中的 productCode
                                    info.setProductCode(bp.getProductCode());
                                    log.warn("ProcessSheetBatchProduct.productId 为空: batchId={}, productCode={}, productName={}",
                                            bp.getBatchId(), bp.getProductCode(), bp.getProductName());
                                }

                                return info;
                            })
                            .collect(Collectors.toList());
                    vo.setBatchProducts(productInfos);
                }
            }

            log.debug("批量填充清机任务详情完成: 任务数={}, 批次数={}",
                    voList.size(), batches.size());

        } catch (Exception e) {
            log.error("批量填充清机任务详情失败", e);
        }
    }

    /**
     * 批量填充生产任务的工序信息
     */
    private void enrichProductionTasksWithSteps(List<WorkflowTaskVO> voList) {
        if (voList == null || voList.isEmpty()) {
            return;
        }

        try {
            List<Long> batchIds = voList.stream()
                    .filter(vo -> vo.getBizId() != null && "PROCESS_BATCH".equals(vo.getBizType()))
                    .map(WorkflowTaskVO::getBizId)
                    .distinct()
                    .collect(Collectors.toList());

            if (batchIds.isEmpty()) {
                return;
            }

            LambdaQueryWrapper<ProcessBatchStep> stepQw = new LambdaQueryWrapper<>();
            stepQw.in(ProcessBatchStep::getBatchId, batchIds)
                    .eq(ProcessBatchStep::getIsDeleted, 0)
                    .orderByAsc(ProcessBatchStep::getBatchId)
                    .orderByAsc(ProcessBatchStep::getSequenceNo);

            List<ProcessBatchStep> allSteps = processBatchStepMapper.selectList(stepQw);

            Map<Long, List<ProcessBatchStep>> stepMap = allSteps.stream()
                    .collect(Collectors.groupingBy(ProcessBatchStep::getBatchId));

            for (WorkflowTaskVO vo : voList) {
                if (vo.getBizId() != null && stepMap.containsKey(vo.getBizId())) {
                    List<ProcessStepVO> stepVOList = stepMap.get(vo.getBizId()).stream()
                            .map(this::convertToProcessStepVO)
                            .collect(Collectors.toList());
                    vo.setSteps(stepVOList);
                }
            }

            log.debug("批量填充工序信息完成: 任务数={}, 工序总数={}", voList.size(), allSteps.size());

        } catch (Exception e) {
            log.error("批量填充工序信息失败", e);
        }
    }

    /**
     * 转换工序实体为VO
     */
    private ProcessStepVO convertToProcessStepVO(ProcessBatchStep step) {
        ProcessStepVO vo = new ProcessStepVO();
        vo.setId(step.getId());
        vo.setBatchId(step.getBatchId());
        vo.setSequenceNo(step.getSequenceNo());
        vo.setOperationCode(step.getOperationCode());
        vo.setOperationName(step.getOperationName());
        vo.setProcessRequirement(step.getProcessRequirement());
        vo.setInspectionMethod(step.getInspectionMethod());
        vo.setInspectionCriteria(step.getInspectionCriteria());
        vo.setExpectedDurationMinutes(step.getExpectedDurationMinutes());
        vo.setPlanStart(step.getPlanStart());
        vo.setPlanEnd(step.getPlanEnd());
        vo.setActualStart(step.getActualStart());
        vo.setActualEnd(step.getActualEnd());
        vo.setNeedInspection(step.getNeedInspection());
        vo.setStatus(step.getStatus());
        vo.setStatusName(getStepStatusName(step.getStatus()));
        vo.setRemark(step.getRemark());
        vo.setOperatorName(step.getOperatorName());

        LocalDateTime now = LocalDateTime.now();

        if (step.getPlanStart() != null && step.getActualStart() == null
                && !"COMPLETED".equals(step.getStatus())) {
            boolean isOverdue = now.isAfter(step.getPlanStart().plusMinutes(5));
            vo.setStartOverdue(isOverdue);
            if (isOverdue) {
                vo.setStartOverdueMinutes(java.time.Duration.between(step.getPlanStart(), now).toMinutes());
            }
        } else {
            vo.setStartOverdue(false);
        }

        if (step.getActualStart() != null && step.getActualEnd() == null
                && step.getPlanEnd() != null && !"COMPLETED".equals(step.getStatus())) {
            boolean isOverdue = now.isAfter(step.getPlanEnd());
            vo.setCompletionOverdue(isOverdue);
            if (isOverdue) {
                vo.setCompletionOverdueMinutes(java.time.Duration.between(step.getPlanEnd(), now).toMinutes());
            }
        } else {
            vo.setCompletionOverdue(false);
        }

        return vo;
    }

    /**
     * 获取工序状态名称
     */
    private String getStepStatusName(String status) {
        if (status == null) {
            return "待排产";
        }
        switch (status) {
            case "PLANNED":
                return "待开工";
            case "READY":
                return "准备就绪";
            case "IN_PROGRESS":
                return "进行中";
            case "COMPLETED":
                return "已完成";
            case "PAUSED":
                return "已暂停";
            case "CANCELLED":
                return "已取消";
            default:
                return status;
        }
    }
}